package com.rz.htk.order.task;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.io.ByteStreams;
import com.rz.htk.order.entity.Order;
import com.rz.htk.order.task.util.HashUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Encoder;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.ServletOutputStream;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ChinaPostTask {

    private DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final MediaType JSON = MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8");

    @Value("${chinaPost.orderReceiveBackUrl}")
    private String orderReceiveBackUrl;
    @Value("${chinaPost.bizBussinessDataUrl}")
    private String bizBussinessDataUrl;
    @Value("${chinaPost.eCompanyId}")
    private String eCompanyId;
    @Value("${chinaPost.mailType}")
    private String mailType;
    @Value("${chinaPost.whCode}")
    private String whCode;
    @Value("${chinaPost.downloadUrl}")
    private String downloadUrl;
    @Value("${chinaPost.apiKey}")
    private String apiKey;

    @Resource
    private OkHttpClient okHttpClient;

    @PostConstruct
    private void init(){
        okHttpClient = generateDefaultOkHttp();
        getBussinessData();
    }

    public void downloadTemplateByOrder(List<Order> orders, ServletOutputStream outputStream) throws Exception {
        StringBuilder sb = new StringBuilder();
        orders.forEach(order -> {
            if(!StringUtils.isEmpty(order.getAfterCode())){
                sb.append(order.getAfterCode()).append(",");
            }
        });
        String barCode = sb.substring(0,sb.length()-1);
        requestZyApi(barCode,outputStream);
    }

    public void downloadTemplateByAfterCode(List<String> afterCodes, ServletOutputStream outputStream) throws Exception {
        StringBuilder sb = new StringBuilder();
        afterCodes.forEach(afterCode -> sb.append(afterCode).append(","));
        String barCode = sb.substring(0,sb.length()-1);
        requestZyApi(barCode,outputStream);
    }

    private void requestZyApi(String barCode,ServletOutputStream outputStream) throws Exception {
        String sign = HashUtil.encryptBASE64(HashUtil.encryptMD5((barCode + apiKey).getBytes()));
        log.info("请求中邮【获取面单】请求barcode {}", barCode);
        log.info("请求中邮【获取面单】请求签名 {}", sign);
        FormBody formBody = new FormBody.Builder()
                .add("barCode", barCode)
                .add("dataDigest", sign)
                .add("version", "1.0")
                .add("ecCompanyId", eCompanyId).build();
        Request request = new Request.Builder()
                .url(downloadUrl)
                .post(formBody)
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            if (response.isSuccessful()) {
                InputStream in = response.body().byteStream();
                ByteStreams.copy(in,outputStream);
            }
        } catch (Exception e) {
            log.error("请求中邮【获取面单】报错 {}", e.getMessage());
        }
    }

    public String orderReceiveBack(Order order) throws Exception {

        FormBody formBody = buildOrderReceiveBackParam(order);
        Request request = new Request.Builder()
                .url(orderReceiveBackUrl)
                .post(formBody)
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            String result = response.body() != null ? response.body().string() : null;
            log.info("请求中邮【订单交运接口】返回数据 result {}", result);
            if (!StringUtils.isEmpty(result)) {
                JSONObject resultObj = JSONObject.parseObject(result);
                String success = resultObj.getString("success");
                if (success.equals("true")) {
                    return resultObj.getString("waybillNo");
                }
            }
        } catch (Exception e) {
            log.error("请求中邮【订单交运接口】报错 {}", e.getMessage());
        }
        return "";
    }

    private FormBody buildOrderReceiveBackParam(Order order) throws Exception {
        JSONObject param = new JSONObject();
        LocalDateTime now = LocalDateTime.now();
        param.put("created_time", now.format(dateTimeFormat));
        param.put("sender_no", eCompanyId);
        param.put("mailType", mailType);
        param.put("wh_code", whCode);
        param.put("logistics_order_no", order.getCommodityCode());
        param.put("weight", order.getWeight());
        param.put("contents_total_weight", order.getWeight());
        param.put("contents_total_value", order.getTotalPrices());
        param.put("pickup_notes", order.getRmk());
        param.put("forecastshut", "0");
        param.put("mail_sign", "2");
        param.put("declare_source","2");
        param.put("declare_type","1");
        param.put("declare_curr_code","RMB");
        param.put("biz_product_no",order.getPrdCode());

        JSONObject receiver = buildReceiver(order);
        param.put("receiver", receiver);
        JSONObject sender = buildSender(order);
        param.put("sender", sender);
        JSONArray cargo = buildCargo(order);
        param.put("items", cargo);
        log.info("请求中邮【订单交运接口】参数 {} ", param.toString());
        String sign = HashUtil.encryptBASE64(HashUtil.encryptMD5((param.toString() + apiKey).getBytes()));
        log.info("请求中邮【订单交运接口】签名 {} ", sign);
        FormBody formBody = new FormBody.Builder()
                .add("logistics_interface", param.toString())
                .add("data_digest", sign)
                .add("msg_type", "B2C_TRADE")
                .add("ecCompanyId", eCompanyId)
                .add("data_type", "JSON").build();
        return formBody;
    }

    private JSONArray buildCargo(Order order) {
        JSONArray cargos = new JSONArray();
        order.getCommodityList().forEach(commodity -> {
            JSONObject object = new JSONObject();
            object.put("cargo_no", commodity.getId());
            object.put("cargo_name", commodity.getCommodityName());
            object.put("cargo_name_en", commodity.getCommodityName());
            object.put("cargo_type_name", commodity.getCommodityName());
            object.put("cargo_type_name_en", "");
            object.put("cargo_quantity", commodity.getAmount());
            object.put("cargo_value", commodity.getCommodityValue());
            object.put("cost", commodity.getCommodityValue());
            object.put("cargo_currency", "USD");
            object.put("carogo_weight", commodity.getWeight());
            object.put("cargo_description", commodity.getCommodityName());
            object.put("unit", order.getUnit());
            cargos.add(object);
        });
        return cargos;
    }

    private JSONObject buildSender(Order order) {
        JSONObject sender = new JSONObject();
        sender.put("name", order.getSenderName());
        sender.put("post_code", order.getSenderPostcode());
        sender.put("nation", order.getDestination());
        sender.put("address", order.getSenderAddress());
        sender.put("linker", order.getSenderName());
        sender.put("mobile", "86"+order.getSenderPhone());
        return sender;
    }

    private JSONObject buildReceiver(Order order) {
        JSONObject receiver = new JSONObject();
        receiver.put("name", order.getRecipientsName());
        receiver.put("post_code", order.getRecipientsPostcode());
        receiver.put("nation", order.getDestination());
        receiver.put("address", order.getRecipientsAddress());
        receiver.put("linker", order.getRecipientsName());
        receiver.put("phone", "86"+order.getRecipientsPhone());
        receiver.put("mobile", "86"+order.getRecipientsPhone());
        return receiver;
    }

    private static OkHttpClient generateDefaultOkHttp() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();


            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier((hostname, session) -> true);
        } catch (Exception e) {
            e.printStackTrace();
        }
        builder.connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);
        return builder.build();
    }

    private void getBussinessData(){
        FormBody formBody = new FormBody.Builder()
                .add("queryType", "queryBusinessType").build();
        Request request = new Request.Builder()
                .url(bizBussinessDataUrl)
                .post(formBody)
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            String result = response.body() != null ? response.body().string() : null;
            log.info("请求中邮【配置数据】返回数据 result {}", result);
            if (!StringUtils.isEmpty(result)) {

            }
        } catch (Exception e) {
            log.error("请求中邮【配置数据】报错 {}", e.getMessage());
        }
    }
}
